package MULE.Model;

import java.util.Random;

/**
 * This class creates a map for the game default or random
 * 
 * 
 * @ author Anastasiya Cotton @ version 1.0 10.04.2013 author Aaron Englebardt @
 * version 1.1 10.16.2013
 * 
 */
public class Map implements java.io.Serializable {

	/**
	 * Serial version ID.
	 */
	private static final long serialVersionUID = -3119324272362560432L;

	/**
	 * Map dimension constants.
	 */
	public static final int ROWS = 5;
	public static final int COLUMNS = 9;
	public static final int CENTER_ROW = 3;
	public static final int CENTER_COLUMN = 5;
	public static final int WIDTH = Tile.WIDTH * COLUMNS;
	public static final int HEIGHT = Tile.HEIGHT * ROWS;

	/**
	 * An enumeration of the possible map types.
	 */
	public enum MapType {
		DEFAULT, RANDOM;
	}

	private Tile[][] map;

	/**
	 * Creates a map of given type.
	 * 
	 * @param type
	 *            Map type as defined in Map.MapType.
	 */
	public Map(MapType type) {
		if (type == MapType.DEFAULT) {
			map = getDefaultMap();
		} else {
			map = generateRandomMap();
		}
	}

	/**
	 * Returns the MapType corresponding to the given string.
	 * 
	 * @param typeStr
	 *            Map type as string.
	 * @return MapType corresponding to string, null if no MapType defined.
	 */
	public static MapType getMapType(String typeStr) {
		// Ignore argument case?
		typeStr = typeStr.toLowerCase();
		// Default type.
		if (typeStr.equals("default")) {
			return Map.MapType.DEFAULT;
		}
		// Random type.
		if (typeStr.equals("random")) {
			return Map.MapType.RANDOM;
		}
		// No type defined.
		return null;
	}

	/**
	 * Returns the tile located at the given coordinates.
	 * 
	 * @param x
	 *            X-coordinate of tile.
	 * @param y
	 *            Y-coordinate of tile.
	 * @return The tile at (x, y).
	 */
	public Tile getTile(int x, int y) {
		return map[y][x];
	}

	/**
	 * Returns a reference to the map's town tile.
	 * 
	 * @return Reference to the map's town tile.
	 */
	public Town getTown() {
		return (Town) map[CENTER_COLUMN - 1][CENTER_ROW - 1];
	}

	/**
	 * Builds and returns the default tile set (map).
	 * 
	 * @return The default tile set.
	 */
	public Tile[][] getDefaultMap() {
		Tile[][] map = new Tile[COLUMNS][ROWS];
		// Row 1
		map[0][0] = new Plain(0, 0);
		map[1][0] = new Plain(1, 0);
		map[2][0] = new Mountain1(2, 0);
		map[3][0] = new Plain(3, 0);
		map[4][0] = new River(4, 0);
		map[5][0] = new Plain(5, 0);
		map[6][0] = new Mountain3(6, 0);
		map[7][0] = new Plain(7, 0);
		map[8][0] = new Plain(8, 0);
		// Row 2
		map[0][1] = new Plain(0, 1);
		map[1][1] = new Mountain1(1, 1);
		map[2][1] = new Plain(2, 1);
		map[3][1] = new Plain(3, 1);
		map[4][1] = new River(4, 1);
		map[5][1] = new Plain(5, 1);
		map[6][1] = new Plain(6, 1);
		map[7][1] = new Plain(7, 1);
		map[8][1] = new Mountain3(8, 1);
		// Row 3
		map[0][2] = new Mountain3(0, 2);
		map[1][2] = new Plain(1, 2);
		map[2][2] = new Plain(2, 2);
		map[3][2] = new Plain(3, 2);
		map[4][2] = new Town(4, 2);
		map[5][2] = new Plain(5, 2);
		map[6][2] = new Plain(6, 2);
		map[7][2] = new Plain(7, 2);
		map[8][2] = new Mountain1(8, 2);
		// Row 4
		map[0][3] = new Plain(0, 3);
		map[1][3] = new Mountain2(1, 3);
		map[2][3] = new Plain(2, 3);
		map[3][3] = new Plain(3, 3);
		map[4][3] = new River(4, 3);
		map[5][3] = new Plain(5, 3);
		map[6][3] = new Mountain2(6, 3);
		map[7][3] = new Plain(7, 3);
		map[8][3] = new Plain(8, 3);
		// Row 5
		map[0][4] = new Plain(0, 4);
		map[1][4] = new Plain(1, 4);
		map[2][4] = new Mountain2(2, 4);
		map[3][4] = new Plain(3, 4);
		map[4][4] = new River(4, 4);
		map[5][4] = new Plain(5, 4);
		map[6][4] = new Plain(6, 4);
		map[7][4] = new Plain(7, 4);
		map[8][4] = new Mountain2(8, 4);

		return map;
	}

	/**
	 * Generates a random tile set (map). The center column contains all river
	 * tiles except for the town which is in the exact center of the map. All
	 * other tiles are either mountains or plains.
	 * 
	 * @return Randomly generated tile set.
	 */
	public Tile[][] generateRandomMap() {
		// Create an empty map.
		Tile[][] map = new Tile[COLUMNS][ROWS];
		Random rand = new Random();
		// Fill in the map.
		for (int i = 0; i < COLUMNS; ++i) {
			for (int j = 0; j < ROWS; ++j) {
				if (i == CENTER_COLUMN - 1) {
					if (j == CENTER_ROW - 1) {
						// Exact center of map contains town.
						map[i][j] = new Town(i, j);
					} else {
						// Center column of map is a river.
						map[i][j] = new River(i, j);
					}
				} else {
					// Randomly pick plain or mountain tile everywhere else.
					int r = rand.nextInt(2);
					if (r == 0) {
						map[i][j] = new Plain(i, j);
					} else {
						// Pick random mountain type (1, 2, or 3).
						r = rand.nextInt(3) + 1;
						map[i][j] = Mountain.getMountainOfType(r, i, j);
					}
				}
			}
		}
		return map;
	}

	/**
	 * Calculates resource production for the given player.
	 * 
	 * @param player
	 *            The player production should be calculated for.
	 * @return Resources produced by the player's land.
	 */
	public Inventory calcProduction(Player player) {
		Inventory production = new Inventory();
		int energyAmnt = player.getInventory().getAmount(Resource.ENERGY);

		// Look at all map tiles.
		for (Tile[] row : map) {
			for (Tile tile : row) {
				// Players owns tile and has enough energy.
				if (tile.getOwner() == player && (energyAmnt--) > 0) {
					production.add(tile.getProduction());
				}
			}
		}
		return production;
	}
}
